package cn.easyutil.util.javaUtil.http;

import cn.easyutil.util.javaUtil.ObjectUtil;
import cn.easyutil.util.javaUtil.StringUtil;
import com.alibaba.fastjson.JSONObject;

import java.io.InputStream;
import java.util.*;

/**
 * http请求封装
 */
public abstract class HttpOperation {

    private HttpReq httpReq;

    private String currentTokenKey = "Set-Cookie";
    private String currentTokenVal;

    public HttpOperation(HttpReq httpReq){
        this.httpReq = httpReq;
    }

    public HttpOperation(String url){
        this(url,HttpMethod.GET);
    }

    public HttpOperation(){
        this.httpReq = new HttpReq();
    }

    public HttpOperation(String url, HttpMethod httpMethod){
        this.httpReq = new HttpReq();
        this.httpReq.setUrl(url);
        this.httpReq.setMethod(httpMethod);
    }

    public void setTokenKey(String tokenKey){
        this.currentTokenKey = tokenKey;
    }

    public HttpReq getHttpReq() {
        return httpReq;
    }

    public HttpRes doUrl(){
        doPre();
        HttpRes httpRes = doUrl(false,this.httpReq,null,null);
        doPost(httpRes);
        return  httpRes;
    }

    public HttpRes doSSLUrl(InputStream certInput, String password){
        doPre();
        HttpRes httpRes = doUrl(true,this.httpReq,certInput,password==null?null:password.toCharArray());
        doPost(httpRes);
        return  httpRes;
    }

    /**
     * 核心逻辑实现
     * @param useSSL
     * @param httpReq
     * @return
     */
    protected abstract HttpRes doUrl(boolean useSSL,HttpReq httpReq,InputStream certInput,char[] password);

    /**
     * 请求前
     */
    private void doPre(){
        if(!StringUtil.isEmpty(this.currentTokenKey) && !StringUtil.isEmpty(this.currentTokenVal)){
            if(this.currentTokenKey.equals("Set-Cookie")){
                this.httpReq.addHeader("Cookie", this.currentTokenVal);
                return;
            }
            this.httpReq.addHeader(this.currentTokenVal, this.currentTokenVal);
        }
    }

    /**
     * 请求后
     */
    private void doPost(HttpRes httpRes){
        Map<String, String> responseHeaders = httpRes.getResponseHeaders();
        if(responseHeaders == null){
            return ;
        }
        Optional<String> first = responseHeaders.keySet().stream().filter(key -> key.equals(currentTokenKey)).findFirst();
        if(first.isPresent()){
            this.currentTokenVal = responseHeaders.get(first.get());
        }
        this.httpReq.setParam(new HashMap());
    }

    /**
     * json数据转form表单提交
     * @param json
     * @return
     */
    public static String jsonToForm(String json){
        if(StringUtil.isEmpty(json)){
            return null;
        }
        Map<String, Object> param = new HashMap<String, Object>();
        StringBuffer listParam = new StringBuffer();
        JSONObject obj = JSONObject.parseObject(json);
        Set<Map.Entry<String, Object>> entrySet = obj.entrySet();
        for (Map.Entry<String, Object> entry : entrySet) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if(ObjectUtil.isBaseObject(value)){
                param.put(key, value);
                continue;
            }
            //循环嵌套map
            if(Map.class.isAssignableFrom(value.getClass())){
                Map<String,Object> map  = (Map<String, Object>) value;
                if(!map.isEmpty()){
                    nestedMap(key, map,listParam, param);
                }
                continue;
            }
            //循环嵌套list
            if(Collection.class.isAssignableFrom(value.getClass())){
                List<Object> list = (List<Object>) value;
                if(!list.isEmpty()){
                    nestedList(key, list, listParam,param);
                }
            }
        }

        //组装参数
        String paramStr = "";
        if (param != null) {
            for (Object key : param.keySet()) {
                paramStr += key + "=";
                paramStr += param.get(key) + "&";
            }
        }
        return paramStr+listParam.toString();
    }

    /**
     * 循环嵌套map
     * @param key	参数key
     * @param map	嵌套的map
     * @param listParam
     * @param param	最终的参数
     */
    private static void nestedMap(String key,Map<String,Object> map,StringBuffer listParam, Map<String, Object> param){
        Set<Map.Entry<String, Object>> entrySet = map.entrySet();
        for (Map.Entry<String, Object> entry : entrySet) {
            String key2 = entry.getKey();
            Object value = entry.getValue();
            if(ObjectUtil.isBaseObject(value)){
                param.put(key+"."+key2, value);
                continue;
            }
            //循环嵌套map
            if(Map.class.isAssignableFrom(value.getClass())){
                Map<String,Object> map2  = (Map<String, Object>) value;
                if(!map.isEmpty()){
                    nestedMap(key+"."+key2, map2,listParam, param);
                }
                continue;
            }
            //循环嵌套list
            if(Collection.class.isAssignableFrom(value.getClass())){
                List<Object> list2 = (List<Object>) value;
                if(!list2.isEmpty()){
                    nestedList(key+"."+key2, list2, listParam,param);
                }
            }
        }
    }

    /**
     * 循环嵌套list
     * @param key
     * @param list
     * @param listParam
     * @param param
     */
    private static void nestedList(String key,List<Object> list,StringBuffer listParam,Map<String, Object> param){
        for (Object obj : list) {
            if(ObjectUtil.isBaseObject(obj)){
                listParam.append("&"+key+"="+obj);
                continue;
            }
            //嵌套map
            if(Map.class.isAssignableFrom(obj.getClass())){
                Map<String,Object> map2  = (Map<String, Object>) obj;
                if(!map2.isEmpty()){
                    nestedMap(key, map2,listParam, param);
                }
                continue;
            }
            //循环嵌套list
            if(Collection.class.isAssignableFrom(obj.getClass())){
                List<Object> list2 = (List<Object>) obj;
                if(!list.isEmpty()){
                    nestedList(key, list2, listParam,param);
                }
            }
        }
    }
}
